package com.cantor.provider.invoker.impl;

import com.cantor.common.exception.ServiceInvokeException;
import com.cantor.common.util.CantorUtil;
import com.cantor.core.pool.CantorExecutorPool;
import com.cantor.provider.invoker.ServiceInvoker;
import com.cantor.provider.pojo.ServiceBoat;
import com.cantor.provider.spi.ExecutableAfterServiceRun;
import com.cantor.provider.spi.ExecutableBeforeServiceRun;
import com.cantor.provider.spi.ExecutableWhileServiceRunning;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.ServiceLoader;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;

/**
 * Provider端的服务执行器默认实现,
 * 因可读性太差, 且不兼容后来的异步Netty处理器, 已弃用, 请移步: com.cantor.provider.invoker.impl.GenericProviderServiceInvoker
 */
@Slf4j
@Deprecated
public class DefaultServiceInvoker implements ServiceInvoker {

    @Override
    public Object invoke(Object impl, String methodName, Class[] paramTypes, Object[] paramValues, ServiceBoat boat) throws Exception {
        // 1.执行与服务同时运行的SPI
        CompletableFuture.runAsync(() -> {
            log.debug("执行业务同时运行的SPI...");
            ServiceLoader.load(ExecutableWhileServiceRunning.class).forEach(ExecutableWhileServiceRunning::execute);
        });
        // 2.执行服务业务
        CompletableFuture future = CompletableFuture.supplyAsync(new Supplier<Object>() {
            @Override
            @SneakyThrows
            public Object get() {
                AtomicReference<Object> atomicResult = new AtomicReference<>(null);
                // 2.1.执行业务前置SPI
                log.debug("执行业务前置SPI...");
                ServiceLoader.load(ExecutableBeforeServiceRun.class).forEach(executable -> executable.execute(paramValues));
                // 2.2.得到具体的Method并执行业务
                Method method = impl.getClass().getDeclaredMethod(methodName, paramTypes);
                atomicResult.set(method.invoke(impl, paramValues));
                // 2.3.执行业务后置SPI
                log.debug("执行业务后置SPI...");
                ServiceLoader.load(ExecutableAfterServiceRun.class).forEach(executable -> {
                    atomicResult.set(executable.execute(atomicResult.get()));
                });
                return atomicResult.get();
            }
        }, CantorExecutorPool.pool())
                .applyToEitherAsync(CompletableFuture.supplyAsync(() -> {
                    CantorUtil.threadSleep(boat.getTimeout());
                    return new TimeoutException();
                }), new Function<Object, Object>() {
                    @Override
                    @SneakyThrows
                    public Object apply(Object r) {
                        if(r instanceof TimeoutException){
                            throw (Throwable) r;
                        }
                        return r;
                    }
                }, CantorExecutorPool.pool())
                .exceptionally(e -> {
                    log.error("执行{}的{}方法时出现异常,可能是超时,也可能是服务本身代码异常", impl.getClass().getName(), methodName);
                    log.error(e.getMessage());
                    // 当调用异常结束, 返回异常包裹异常ServiceInvokeException
                    return new ServiceInvokeException(e.getMessage());
                });
        return future.join();
    }
}
